from website.models import Profile, Recipe, Recipe_Ingredient, Filter, Ingredient_Filter, Rating, Picture
from website.forms import RegisterMail, UserProfileForm, ChangeProfileForm, RecipeForm, IngredientForm, UserFilterForm, IngredientFilterForm

from django.db.models import Q, Max, Avg
from django.contrib.auth.models import User
from django.contrib.auth import logout, views

from random import randint
from django.shortcuts import get_object_or_404, render_to_response, redirect
from django.template import RequestContext
from django.forms.models import inlineformset_factory
from django.contrib.auth.tokens import default_token_generator as token
from django.core.mail import send_mail

"""
@author: Daniel Geymayer, Alexander Fruehwirth, Michael Joergler
@version: 1.0
"""

def index(request):
    """Shows the start page"""
    content = "Welcome to cookit!"
    return render_to_response('base.html', {'title': "Start page", 'content': content}, context_instance=RequestContext(request))

def site_notice(request):
    """Shows the site notice page"""
    content = "Site notice"
    return render_to_response('base.html', {'title': "Site notice", 'content': content}, context_instance=RequestContext(request))

def contact(request):
    """Shows the contact page"""
    content = """
    <p>
        <strong>Team cookit</strong><br>
        Krottendorf 8<br>
        8605 Kapfenberg<br>
    </p>
    <p>
        Alexander Fr&uuml;hwirth<br>
        Daniel Geymayer<br>
        Michael J&omul;rgler
    </p>
    """
    return render_to_response('base.html', {'title': "Contact", 'content': content}, context_instance=RequestContext(request))

def recipes(request):
    if request.user.is_authenticated() and request.session['user_filter'] == "true":
        """User logged in"""
        title = "All recipes - filtered"
        recipes = get_filtered_recipes(request)
    else:
        """User not logged in or filter off"""
        title = "All recipes"
        recipes = Recipe.objects.all()
    
    return render_to_response('recipes.html', {'title' : title,
                                               'recipes': recipes}, context_instance=RequestContext(request))
    
def my_recipes(request):
    """Lists user's recipes"""
    if request.user.is_authenticated():
        title = "My recipes"
        recipes = Recipe.objects.all().filter(user=request.user)
    
    return render_to_response('recipes.html', {'title' : title,
                                               'recipes': recipes}, context_instance=RequestContext(request))

def get_filtered_recipes(request):
    """Returns recipes according to the filter set"""
    user_filter = Filter.objects.all().get(user=request.user)
    ingredients_filter = Ingredient_Filter.objects.all().filter(filter=user_filter)
    
    # Difficulty filter
    difficulty_filter = Q()
    if user_filter.difficulty is not None:
        difficulty_filter = Q(difficulty=user_filter.difficulty)
    
    # Vegetarian filter
    vegetarian_filter = Q()
    if user_filter.vegetarian is not None:
        vegetarian_filter = Q(vegetarian = user_filter.vegetarian)
    
    # Ingredients filter
    ingredients_ex = []
    ingredients_noex = []
    for i in ingredients_filter:
        if i.exclude:
            ingredients_ex.append(i.ingredient)
        else:
            ingredients_noex.append(i.ingredient)
    
    q_rec_ing = Q()
    q_rec_ing2 = Q()
    
    # exclude recipes which have the ingredient but should not
    for recipe in Recipe.objects.all():
        for i in ingredients_ex:
            if i.lower() in list(map(lambda x: x.name.lower(), recipe.get_ingredients())):
                q_rec_ing &= ~Q(id=recipe.id)
    
    # exclude recipes which do not have the ingredient but should
    for recipe in Recipe.objects.all():
        for i in ingredients_noex:
            if i.lower() not in list(map(lambda x: x.name.lower(), recipe.get_ingredients())):
                q_rec_ing2 &= ~Q(id=recipe.id)
    
    return Recipe.objects.all().filter(difficulty_filter & vegetarian_filter & q_rec_ing & q_rec_ing2)

def recipe(request, recipe_id, beginning=None, pre_title=None):
    """Displays a certain recipe based on its ID"""
    recipe = Recipe.objects.get(pk=recipe_id)
    ingredients = Recipe_Ingredient.objects.all().filter(recipe_id=recipe_id)
    avg_rating = avg_ratings(request, recipe_id)
    rating_user = get_user_rating(request, recipe_id)
    pictures = Picture.objects.all().filter(recipe_id=recipe_id)
    
    return render_to_response('recipe.html', {'pre_title': pre_title,
                                              'beginning': beginning,
                                              'recipe': recipe,
                                              'ingredients' : ingredients,
                                              'rating' : avg_rating,
                                              'rating_user' : rating_user,
                                              'pictures' : pictures
                                              }, context_instance=RequestContext(request))

def avg_ratings(request, recipe_id):
    """ Calculates average ratings """
    ratings = Rating.objects.filter(recipe_id=recipe_id).aggregate(Avg('rating'))
    
    if ratings['rating__avg'] is not None:
        rating = round(ratings['rating__avg'], 1)
        if (rating * 10) % 2 != 0:
            rating = rating + 0.1
        rating = str(rating)
    else:
        rating = "None"
    
    return rating

def get_user_rating(request, recipe_id):
    """ returns current user rating """
    try:
        rating_user = Rating.objects.get(recipe_id=recipe_id, user_id = request.user.pk)
        rating = rating_user.rating
    except:
        rating = 0
    return rating
    
def login_user(request):
    """ login procedure """   
    return views.login(request, template_name='login_form.html')

def logout_user(request):
    """ logout procedure """   

    logout(request)
    return redirect('/login', permanent=True)

def register(request):
    """ register procedure including sending activation link via mail """
    if request.method == 'POST':
        form = RegisterMail(request.POST)
        if form.is_valid():
            newUser = User.objects.create_user(request.POST['username'], 
                                               request.POST['email'], 
                                               request.POST['password'])
            tk = token.make_token(newUser)
            server = request.build_absolute_uri('../activate/')
            newUser.first_name = tk
            newUser.is_active = False
            newUser.save()
            send_mail('Activation link for cookit',
                      'Hi '+newUser.username +'! This is your activation link for your cookit account: '+server+'?user='+newUser.username+ '&token=' +tk,
                      'from',[newUser.email], fail_silently=False)
            return render_to_response('base.html', {'title': "Activate your account", 
                                                        'content': "Your account was created. To activate it click the link in the email sent to your email address",
                                                    }, context_instance=RequestContext(request))
    else:
        form = RegisterMail()
    
    return render_to_response('register_form.html', {'title': "Register", 'form': form}, context_instance=RequestContext(request))

def activate_user(request):
    """" activation procedure when user opens link"""
    try:
        user=request.GET['user']
        token = request.GET['token'] 
        u = User.objects.get(username__exact=user)
        if u.first_name == token:
            u.is_active = True
            u.first_name = ''
            u.save() 
            return render_to_response('base.html', {'title': "Cookit", 
                                            'content': "User was activated! Now you can get started!"}, context_instance=RequestContext(request))
        else:
            return render_to_response('base.html', {'title': "Cookit", 
                                                    'content': "Please use your activation link in the email sent to you! If this does not work register again please."}
                                      ,context_instance=RequestContext(request))
    except:
        return render_to_response('base.html', {'content': "Please use your activation link in the email sent to you!", 'title': "cookit"}
                                      ,context_instance=RequestContext(request))

def change_profile(request): 
    """ generates User Profile Form and updates changes"""   
    # check if user already made changes
    if request.method == 'POST':
        change_form = ChangeProfileForm(request.POST)
        # check if form is valid - doesn't work yet
        if change_form.is_valid():
            mod_user = request.user;
            # setting new user information
            mod_user.first_name = request.POST['first_name']
            mod_user.last_name = request.POST['last_name']
            mod_user.email = request.POST['email']
            mod_user.save()
            request.user = mod_user
            #redirect to profile page
            profile_form = UserProfileForm(instance=request.user)
            return render_to_response('user_profile.html', {'title': "My profile", 'form': profile_form}, context_instance=RequestContext(request))
    else:
        change_form = ChangeProfileForm(instance=request.user)
        return render_to_response('change_profile.html', {'title': "My profile", 'form': change_form}, context_instance=RequestContext(request))
        
def change_pw(request):
    """ change password procedure """
    return views.password_change(request, template_name="change_password.html", post_change_redirect="/profile")

def user_profile(request):
    """ returns data for user_profile site """
    # Initial settings:
    Profile.objects.get_or_create(user=request.user)
    Filter.objects.get_or_create(user=request.user)
    user_filter = Filter.objects.get(user=request.user)
    if user_filter.active:
        request.session['user_filter'] = "true"
    else:
        request.session['user_filter'] = "false"
    
    profile_form = UserProfileForm(instance=request.user)
    return render_to_response('user_profile.html', {'title': "My profile", 'form': profile_form}, context_instance=RequestContext(request))

def user_filter(request):
    """Display a user filter form so the user can choose what should be presented"""
    if request.user.is_authenticated():
        user_filter = Filter.objects.get(user=request.user)
        IngredientFilterInlineFormset = inlineformset_factory(Filter, Ingredient_Filter, form=IngredientFilterForm, extra=1)
        
        if request.method == 'POST':
            filter_form = UserFilterForm(request.POST, request.FILES, instance=user_filter)
            filter_formset = IngredientFilterInlineFormset(request.POST, request.FILES, instance=user_filter)
            if filter_form.is_valid():
                form_data = filter_form.save(commit=False)
                form_data.user = request.user
                filter_formset = IngredientFilterInlineFormset(request.POST, request.FILES, instance=form_data)
                if filter_formset.is_valid():
                    form_data.save()
                    filter_formset.save()
                    return redirect("/filter", permanent=True)
        else:
            filter_form = UserFilterForm(instance=user_filter)
            filter_formset = IngredientFilterInlineFormset(instance=user_filter)
        
        return render_to_response('recipe_form.html', {'title': "My filter",
                                                       'button' : "Save filter",
                                                       'form': filter_form,
                                                       'formset': filter_formset,
                                                       'form_type': "ingredient_filter_set"}, context_instance=RequestContext(request))
    else:
        return redirect('/login', permanent=True)

def use_filter(request):
    """ activates user filter """
    if request.user.is_authenticated():
        user_filter = Filter.objects.get(user=request.user)
        if request.method == 'POST':
            if user_filter.active:
                user_filter.active = False
                request.session['user_filter'] = "false"
            else:
                user_filter.active = True
                request.session['user_filter'] = "true"
            user_filter.save()
        return redirect(request.POST['res_url'], permanent=True)
    else:
        return redirect('/login', permanent=True)

def create_recipe(request):
    """Creates a new recipe"""
    if request.user.is_authenticated():
        return generate_recipe_form(request, title="Create recipe", button="Create recipe")
    else:
        return redirect('/login', permanent=True)

def edit_recipe(request, recipe_id):
    """Edit an existing recipe"""
    recipe = get_object_or_404(Recipe, pk=recipe_id)
    if request.user.is_authenticated() and recipe.user == request.user:
        return generate_recipe_form(request, title="Edit recipe", button="Update recipe", recipe=recipe)
    else:
        return redirect('/login', permanent=True)

def generate_recipe_form(request, title="No title", button="No caption", recipe=None):
    """Create or edit a recipe"""
    IngredientInlineFormset = inlineformset_factory(Recipe, Recipe_Ingredient, form=IngredientForm, extra=1)
    
    if request.method == 'POST':
        recipe_form = RecipeForm(request.POST, request.FILES, instance=recipe)

        ingredient_formset = IngredientInlineFormset(request.POST, request.FILES, instance=recipe)
        if recipe_form.is_valid():
            form_data = recipe_form.save(commit=False)
            form_data.user = request.user
            ingredient_formset = IngredientInlineFormset(request.POST, request.FILES, instance=form_data)
            if ingredient_formset.is_valid():
                form_data.save()
                ingredient_formset.save()
                return redirect(("%s%d") % ('/recipe/', form_data.pk), permanent=True)
    else:
        recipe_form = RecipeForm(instance=recipe)
        ingredient_formset = IngredientInlineFormset(instance=recipe)
    
    return render_to_response('recipe_form.html', {'title': title,
                                                   'button' : button,
                                                   'form': recipe_form,
                                                   'formset': ingredient_formset,
                                                   'form_type': "recipe_ingredient_set"}, context_instance=RequestContext(request))

def search_recipe(request):
    """ classic search method """
    if request.method == 'POST' and request.POST['searchstring'] != "":
        searchstring = request.POST['searchstring']

        if request.user.is_authenticated() and request.session['user_filter'] == "true":
            recipes = get_filtered_recipes(request)
        else:
            recipes = Recipe.objects
        
        recipes = recipes.filter(Q(title__icontains = searchstring) | Q(description__icontains = searchstring))
        if len(recipes) == 1:
            return recipe(request, recipes[0].pk)
        elif len(recipes) > 0:
            return render_to_response('recipes.html', {'title' : "Searched Recipes - '"+searchstring+"'",
                                                       'recipes': recipes}, context_instance=RequestContext(request))
        else:      
            return render_to_response('base.html', {'title': "Nothing found!", 'content': "OOPS! We're sorry! No entry for '"+searchstring+"' found! :("}, context_instance=RequestContext(request))
    else:
        return render_to_response('base.html', {'title': "Nothing found!", 'content': "OOOPS! Forgot the search term? ;)"}, context_instance=RequestContext(request))

def delete_recipe(request, recipe_id):
    """ recipe delete procedure """
    recipe = Recipe.objects.get(pk=recipe_id)
    if request.user.is_authenticated() and recipe.user == request.user:
        recipe.delete()
        return redirect('/my_recipes', permanent=True)
    return redirect('/login', permanent=True)

def random_recipe(request):
    """Displays a certain recipe based on its ID"""
    if request.user.is_authenticated() and request.session['user_filter'] == "true":
        recipes = get_filtered_recipes(request)
    else:
        recipes = Recipe.objects
    
    amount = recipes.aggregate(Max('pk'))['pk__max']
    if amount == None:
        return render_to_response('recipes.html', {'title': "Recipe"}, context_instance=RequestContext(request))
    recipe_id = get_rnd_recipe(recipes, amount)
    
    if request.user.is_authenticated() is False:
        beginning = "Our recommendation for you! Don't like it? Register!"
    elif request.session['user_filter'] == "false" and request.user.is_authenticated():
        beginning = "Our recommendation for you! Don't like it? Change your filter!"
    else:
        beginning="Our recommendation for you, according to your filter!"
        
    pre_title = "cookit"
    return recipe(request, recipe_id=recipe_id, beginning=beginning, pre_title=pre_title)

def get_rnd_recipe(recipes, amount):
    """ Chooses a random recipe. If no recipe was found itself again"""
    recipe_id = randint(1, amount)
    
    if recipes.filter(pk=recipe_id):
        return recipes.get(pk=recipe_id).pk
    else:
        return get_rnd_recipe(recipes, amount)

def rate(request):
    """ Rating procedure for recipes """
    if request.user.is_authenticated():
        if request.method == 'POST':
            try:    
                rate = Rating.objects.get(recipe = request.POST['recipe'], user = request.user.pk)
            except:
                recipe = get_object_or_404(Recipe, pk=request.POST['recipe'])
                user = get_object_or_404(User, pk=request.user.pk)
                rating = Rating(recipe=recipe, user = user, rating = request.POST['rating'])
                rating.save()
                return redirect('/recipe/'+request.POST['recipe'], permanent=True)
            
            rate.rating = request.POST['rating']
            rate.save()
    
         
            return redirect('/recipe/'+request.POST['recipe'], permanent=True)
        else:
            return render_to_response('base.html', {'title': "Nothing found!", 'content': "OOOPS! Buggy ;)"}, context_instance=RequestContext(request))
    else:
        return redirect('/login', permanent=True)

    
    

def ajax_search(request):
    """ django method for ajax search request """
    if request.is_ajax():
        q = request.GET.get('q')
        if q is not None:     
            results = Recipe.objects.filter(
                Q(title__icontains = q) |
                Q(description__icontains = q)
                ).order_by('title')
                
            return render_to_response('ajax_search.html', {
                   'recipes': results,
            },
                context_instance = RequestContext(request))


